"""
elio框架服务端。
"""
import threading
import typing

import grpc
from grpc.experimental import aio  # type: ignore
from loguru import logger
from socketio import AsyncServer, get_tornado_handler  # type: ignore
from tornado import web

from .core import (
    get_event_loop, get_local_ip, get_thread_pool_executor, register_to_server, unregister_from_server,
    shutdown
)  # type: ignore

_grpcServer: typing.Optional[aio.Server] = None


class RpcMethodHookHandler(grpc.RpcMethodHandler):
    """
    Attributes:
        flow: 总流量。
    """
    flow: int = 0

    def __init__(self, origin: grpc.RpcMethodHandler) -> None:
        super().__init__()
        setattr(self, 'request_streaming', getattr(origin, 'request_streaming'))
        setattr(self, 'response_streaming', getattr(origin, 'response_streaming'))
        setattr(self, 'stream_stream', getattr(origin, 'stream_stream'))
        setattr(self, 'unary_stream', getattr(origin, 'unary_stream'))
        setattr(self, 'unary_unary', getattr(origin, 'unary_unary'))
        setattr(self, 'stream_unary', getattr(origin, 'stream_unary'))
        ori_request_deserializer = getattr(origin, 'request_deserializer')

        def request_deserializer(*args):
            """
            请求解码。
            """
            if args:
                self.__class__.flow += len(args[0])
            return ori_request_deserializer(*args)

        self.request_deserializer = request_deserializer
        ori_response_serializer = getattr(origin, 'response_serializer')

        def response_serializer(*args):
            """
            响应编码。
            """
            ret = ori_response_serializer(*args)
            self.__class__.flow += len(ret)
            return ret

        self.response_serializer = response_serializer


class MyInterceptor(aio.ServerInterceptor):

    async def intercept_service(
            self, continuation: typing.Callable[
                [grpc.HandlerCallDetails], typing.Awaitable[grpc.RpcMethodHandler]
            ], handler_call_details: grpc.HandlerCallDetails
    ) -> grpc.RpcMethodHandler:
        handler = await continuation(handler_call_details)
        return RpcMethodHookHandler(handler)


async def start(debug: bool = False, port: int = 8000):
    """
    启动服务端。
    :param debug: 调试模式。
    :param port: GRPC端口。
    """
    global _grpcServer
    logger.info('Server started on %s.' % threading.current_thread().name)
    # start rpc service
    _grpcServer = aio.server(
        get_thread_pool_executor(),
        interceptors=[MyInterceptor()],
        options=[
            ('grpc.so_reuseport', 0),
            ('grpc.max_send_message_length', 100 * 1024 * 1024),
            ('grpc.max_receive_message_length', 100 * 1024 * 1024),
            ('grpc.enable_retries', 1),
            ('grpc.keepalive_permit_without_calls', 0),
            ('grpc.keepalive_timeout_ms', 5000),
            ('grpc.keepalive_time_ms', 10000),
        ]
    )
    _grpcServer.add_insecure_port(f'[::]:{port}')
    # 启动grpc服务
    await _grpcServer.start()
    host = get_local_ip()
    logger.success(f'Grpc URL: http://{host}:{port}')
    # sockio框架支持
    sio = AsyncServer(async_mode='tornado', logger=True, cors_allowed_origins='*')
    # tornado应用
    app = web.Application([
        (r"/socket.io/", get_tornado_handler(sio))
    ])
    app.listen(8001)
    # 需要服务
    await register_to_server(_grpcServer, sio, app, debug=debug)
    logger.success(f'Http URL: http://{host}:8001')
    # 保持运行状态
    try:
        await _grpcServer.wait_for_termination()
    except KeyboardInterrupt:
        await _grpcServer.stop(None)
    await unregister_from_server()
    _grpcServer = None
    shutdown()
    logger.info('Server stopped.')


async def stop():
    """
    停止服务端。
    """
    if not _grpcServer:
        return
    await _grpcServer.stop(True)


if __name__ == '__main__':
    loop = get_event_loop()
    loop.run_until_complete(start(True))
    loop.close()
